﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Collections;

namespace CrazyTalk.Common
{
   
    class NumberConverter
    {
        private string charTable;
        private int baseNumber;

        public NumberConverter()
            : this("0123456789ABCDF")
        {
        }

        public NumberConverter(string table)
        {
            charTable = table;
            baseNumber = table.Length;
        }

        public int CharToNumber(char ch)
        {
            return charTable.IndexOf(ch);
        }

        public char NumberToChar(int val)
        {
            return charTable[val];
        }

        public long Parse(string str)
        {
            int l = str.Length, i = 0;
            long ret = 0;
            while (i < l)
            {
                ret = ret * baseNumber + charTable.IndexOf(str[i++]);
            }
            return ret;
        }

        public unsafe int NumberToArray(long val, char[] buffer, int bufLen, int fillLen, int offset)
        {
            int l = 0;
            fixed (char* p = buffer)
            {
                char* ptr = p + bufLen - 1;
                while (val > 0 && l < fillLen)
                {
                    *((ptr--) - offset) = charTable[(int)(val % baseNumber)];
                    val /= baseNumber;
                    l++;
                }
            }
            return l;
        }

        public unsafe string NumberToString(long val)
        {
            int bufLen = 32, l = 0;
            char[] buffer = new char[bufLen];
            fixed (char* p = buffer)
            {
                char* ptr = p + bufLen - 1;
                while (val > 0 && l < bufLen)
                {
                    *(ptr--) = charTable[(int)(val % baseNumber)];
                    val /= baseNumber;
                    l++;
                }
            }
            return new string(buffer, bufLen - l, l);
        }

        static long Power(int val, int baseNumber)
        {
            long ret = 1;
            for (int i = 0; i < baseNumber; i++)
            {
                ret *= val;
            }
            return ret;
        }
    }

    public sealed class SequenceNo
    {
      

        static NumberConverter[] SequenceGen = new NumberConverter[] { 
          
                new NumberConverter("2aAuoE4GIe5j9RXtMqkQPW10xmN73CLh8YSdTnzK-rHfJOvZlcV6DUipsB$Fybgw"),
                new NumberConverter("MSgl7$ZeuQObGUpdyvKVjBWq0kz6fsH-T39mX2Ecwi5YnoC1IJ8xRaF4thPDANrL"),
                new NumberConverter("4T1GK03vgmc$9u5FWxpMlRPtf8skNwdXnAZLj2iJOEQyBV6-oYzCbeHa7DhSIUrq"),
                new NumberConverter("32D-MiRUBXyZ5apG6vzowcu9nsIeQVC7hbm1H0gAEWtFklYTNLJOPqrd48Kjf$xS"),
                new NumberConverter("HsqTjk03EvgSfpO5KlL9P$tznIyAoFcNWDrmw6hXG41R2QiJb8BdVxMU7-aYueCZ"),
                new NumberConverter("BMzS$a9CukqHyRwUYgVl80xe-Wn2PNoOs3DdJIF5rphcvtGTj6f1KLb7QAXZi4mE"),
                new NumberConverter("wONvDG6CRUsJFKi0EL7Sgo5bP2T8zuXqBVnhfZWl3km$dYy4eQAc-Mt9Ixj1rHap"),
                new NumberConverter("359yY6RowVI$7FxpAGXZhtmnScLiqBf1NDsTM-aW0PdU8u4CvkElbjrHKOQzegJ2"),
                new NumberConverter("pEdwLTU7ezVDMHjbZFq04vXcKmB2YisJRrlxC8nQI$6aGgt-WuNOoySkP1Af39h5"),
                new NumberConverter("ABnabrKPYJj6mzIkxERdGNTW4s8De5FwO9V2uLXqh-yfHc3oltg017ivZMSpUC$Q"),
                new NumberConverter("5opZYDvirc0IQtEagOUkPBxJTdKXqf7V6SRNne9W-$8G1LHw2u4FjAzsyb3mlChM"),
                new NumberConverter("UV8yNmr5E0lT2ZL7GYcxew$3XfdHWDjh41uSIQaJ6-9iPgtOCzpMqvbkRAKoBnsF"),
                new NumberConverter("K7R1fqtn-GvawOg0lC8WUJr4QM$A2j9XT3HIBpmSEzVd65iLbcyxZDhFYeoPuskN"),
                new NumberConverter("ASCvBUwzTmOYyIxNgpiaj5-JV9uh8PWL63Mfqlt$R0Xdbs1rGDZon7K2HeFkE4cQ"),
                new NumberConverter("G-LswIaurj3gZHhT9zK0pVQ$YJB1O2WNFbUkiA57fn8ECtXD6xodqmMlcRPe4vyS"),
                new NumberConverter("HkQ6t3r$vFO9TEsjw4uWGzYXLg7MxU02CIySVNK58nfdZ1RaehmAoBlPJ-pDqcbi"),
                new NumberConverter("FMzCJWOdqsTUL$8ISpuQm-H6cfAZb45el9K0271yGDPtiNxRnaoBjkhVwrYgEv3X"),
                new NumberConverter("jviAe9HMqwEhoUYPf0r6O1z5X42IVQmN7aClWtcbDSKsT$RdFB-J3xZpykgL8Gun"),
                new NumberConverter("BufJOwzrSG$-gCcZbV0FMTK7ARlp8xP5aqYXH43NE6omvL1ky2te9hDjdWIsQUni"),
                new NumberConverter("upSrf6JUQg2FjcCwP$o8-m5xkq0i3BD7OKsAnG4vdWHRYlztLIXENaZ1eV9yMbTh"),
                new NumberConverter("WzsPm52HvxQXdkN$q6UoawhngfJF4CjA1tpTyS8BDILO7-Vu39r0EbcZKGeMilRY"),
                new NumberConverter("AFVmwq1JzKgMcOinHTC-Il8S9GRvx4ZX5jDuak2N3h6pyQ$rPseBW7UY0EfobLdt"),
                new NumberConverter("pCFx9mHbRywdhSVqJXZ1ME-vKorQ6OnzDAtg40eYc7kUBifWPjGuN8LT3Il5$s2a"),
                new NumberConverter("5$LUZnjHt0PEVSie8FyQ6xTzmNYqOJgshpMBIA2o134cwG9ld-Dfr7vKaWkCRubX"),
                new NumberConverter("MZXh-PEv9BQ4uw1aLmDU8z2itKk0YxWACcGSlRoHnNdgfrFeJ6sVpOITjyqb735$"),
                new NumberConverter("gHxNkery-0jpQM3568dLA4UnDousb9WTwI$OtmqaJlRZXSz2fYPKG1BciCEvhV7F"),
                new NumberConverter("VHwASiBDC-0Jcm6gsp4zWvtr9OXjdyqMYUELble3QNKa1u275fF$oPThR8GIZnxk"),
                new NumberConverter("5fh-Xm14AyT6WLtIMRj8sxUGBgzbnav2qDVNE3cKd7rwoO0CHklpiQPFJY$ueS9Z"),
                new NumberConverter("2SDMqY5ItQbp6aRoexT1uAHUrLCnEiZ7mKzP9kGghW$Nyc0f34Ow-FlsBjXVJ8dv"),
                new NumberConverter("vQ2od-ctbmLMCuVDHXl7Ne6Ua1FPArJRSpYZfB03WTGEyOnIKg8xk$w9hj5qz4si"),
                new NumberConverter("U-$RP2j4YnixKvcFLz7sdWqOwABy1NECgQhpI9mDZ5HkGrtSou8e3b6l0VXMfaJT"),
                new NumberConverter("WXFyClx97vMaJ8G5Lq26Hb3wNonpieRs4DOjd-EI$1fPVghzQTu0ktrAUScYmBKZ"),
                new NumberConverter("YVT9wXWHht58srRe7oUIiKACFELMNnDxf3k$4a1qyjQpul6bv2OGdBzJSZ-g0Pmc"),
                new NumberConverter("fFYmBXUhnkP0zLKS4jRCQ3EVIZgucNdopO7eAMJGqrW$tw8-yTbaslDH129vx65i"),
                new NumberConverter("CnMWDpFhK6focJkT9dw3r-uvyVU5zaLtS2gxPij7BsEZ4e$YIqOGb0Q8mNRX1AlH"),
                new NumberConverter("liDXbn-Orjsqg9kAVtey31BSRQ20F8xCHZwPWT6d4Ga5JpYohMEUNvfucm7Iz$KL"),
                new NumberConverter("qjd9HLh6l4yzXANn1MOt2WkS-EvpR0w5uiFU8KVPf$cIobBQJD3ZgYmGxC7Tesra"),
                new NumberConverter("Au1lytegr-B3nPYL5VSCxWQZ7sTv9NwkH$8qbMORcIXf6hKadozmEGiJDFU04pj2"),
                new NumberConverter("3NlsHfke5-YZ$oLSOvGJR0QpBXW8nM4ur6ctxdEy2ImPwAba7ChUTD19zqgiFVjK"),
                new NumberConverter("wjlvDWZmbLF6A-r2sq3aiVOd4Tuz0UnQM9SEPhKcYxt5yok$7NgCJBpHG1fXRIe8"),
                new NumberConverter("aoi1Uec8QV3vkKmBgyuOfS-9EAwJshxz5lR6DpPM$dn0F4YtIZ2bjHN7qTXGWCLr"),
                new NumberConverter("Z6mwrb-oQORveyx9UuzBcC8jKNHa17hfT4P5IkAngFGLsWSqYdlpD02M$tVEJXi3"),
                new NumberConverter("knOXUstpqAWNzuxr3Q1MJwIS27CLBhYHZ-c58oKjiyv6TdG04ePlFR$gVmEDbaf9"),
                new NumberConverter("jDy$GqlC7JfRzF-Pi6MYSh093peBQw8KOsVIkUoAt4d1gZrEx5cXH2mvNnuWLabT"),
                new NumberConverter("AQ67rjiLNBhK3$Xc-WGIMf5HEV2waR0POdvJYoUDbT9zgZxFSkmqepul8tyCns41"),
                new NumberConverter("8P3d6GELB0v-XArtYofCsQyicMzWmwZbS5p1IND4FJeRku7H29xqTjOlaV$hUgKn"),
                new NumberConverter("SHYLFrc8hZ0jue-mDpUl1kPqz5WwJMoQfCvKGix7On9abRysE6TI3gAdtXB24$VN"),
                new NumberConverter("kX$ZjaNSvHFCWp5Q8mV6tLKz3AdfOnyo-us7UI2il0YqMxB1bw4RDePJE9cgGrTh"),
                new NumberConverter("OXEcvzuodiGnpTS5$U-LfMZFRWxQqVk1tDJsgY4b08rICaNhHAeKmj9ywl26P7B3"),
                new NumberConverter("yFuR4bNOPJQYcAzw0H2X-KDCsa1penihEqV7k6fv$B8WMxTlt9LjSZ3g5mdUoIrG"),
                new NumberConverter("flFmgqCve6ToBkwx4IsNQ$Gicr50W1LROVtYha39zP2H-JSEnbUDjM8pXZ7ydAKu"),
                new NumberConverter("n2PiwJBUFjT0y3pRVsExZ5mzN98IeHXl7Qa$uhMWY14-vCkSgdLrtKAfGbDo6qcO"),
                new NumberConverter("FjuZYrUiRmOV1o$DKgW0vbpfBndMJXCS82qEA9xw5hN7-ceQP3LaIy6lzGHs4Tkt"),
                new NumberConverter("VvK03k1CrhwEGcjd8D$OFnARu7P4t9g5UZlBQiXq6MmozyTNYfe2I-bpaxHsLWJS"),
                new NumberConverter("0spiwcKShCIz5TRxf2ZBPg$OoyHJWXL6vue48kNqGAFrbjaDV7EQU1YdtM-n93ml"),
                new NumberConverter("qC-8lOpychoEM4m3K2rLH1gubPDjsTYNG75VkXZARJniI6$vdwaFBeztU0WS9Qfx"),
                new NumberConverter("9V$G2NOqYjyzJ0daMR81rKChDIwf3AxPEcbo6mnHXskWg-TUZv4lu7LpFQ5iSteB"),
                new NumberConverter("lfpmTsRdewU1Zg-CnN546DL2EjSqc$tizIhy9axWMH70VJFYKrvuQbBPAkOX8o3G"),
                new NumberConverter("5p2Iy067VUej9OWvXsSq-tAG1FiRDJMmTYzoKxgNlwZC8fauHhLcEBn4krPdQb$3"),
                new NumberConverter("9sJhQgbW7623PxAOmpBUylXEjn5Viz0C1K8NStcfFuYHGowrk$4ZaTMRLD-qeIvd"),
                new NumberConverter("6x28tp1yHWNAMP43sOnmvXdZweuFko7-zE5IbgqjlBK0DJC9G$hSTLVcUaRYriQf"),
                new NumberConverter("RNA7IsT8SyvnCcPkZu9q0pfxtOr4Xe$3zmWh2-dEQajJ6UKgBMi1YGLblDFwoHV5"),
                new NumberConverter("$qpJ0cfX8xILyFlN1Aw5vtRbTz4khrGB6CSOg7jWnDse29aUVumiMQd3PH-EZoYK"),
                new NumberConverter("e7FrsSfwPQHn0ibNIcGu3XoZLKyWCk$xJg4vpmV2AzE-915dYRjtTq8BMaOUh6lD"),
                };

        static NumberConverter converter = new NumberConverter("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz$-");
        private static DateTime baseTime = new DateTime(2000, 1, 1);
        private char[] buffer;
        static int Counter;
        static object syncRoot = new object();
        static DateTime lastCreateTime = DateTime.Now;
        static Random rnd = new Random();

        public SequenceNo()
        {
            buffer = new char[] { 'W', '2', '0', '0', '0', '0', '0', '0', '0', '0' };
            int ts = Convert.ToInt32((DateTime.Now - baseTime).TotalSeconds);
            CheckCounter();
            converter.NumberToArray(ts, buffer, 10, 6, 2);
            converter.NumberToArray(Counter++ % 1024, buffer, 10, 2, 0);
        }

        private void CheckCounter()
        {
            lock (syncRoot)
            {
                if ((DateTime.Now - lastCreateTime).TotalMilliseconds >= 1000)
                {
                    System.Threading.Interlocked.Exchange(ref Counter, 0);
                    lastCreateTime = DateTime.Now;
                }               
            }
        }

        private SequenceNo(int t)
        {
            CheckCounter();
        }

        static int GetNextRandomSeed(int max)
        {
            lock (syncRoot)
            {
                return rnd.Next(max);
            }
        }

        //public static SequenceNo CreateByMix(char type)
        //{
        //    SequenceNo id = new SequenceNo();

        //    int seed = GetNextRandomSeed(32);
        //    id.buffer[0] = type;
        //    id.buffer[1] = converter.NumberToChar(seed);

        //    for (int i = 0; i < 8; i++)
        //    {
        //        char tmp = id.buffer[2];
        //        id.buffer[2] = id.buffer[2 + SeedArray[seed, i]];
        //        id.buffer[2 + SeedArray[seed, i]] = tmp;
        //    }

        //    return id;
        //}

        private static char CalcHash(char[] str)
        {
            int i = 0;
            int sum = 0;
            int[] dg = new int[] { 7, 9, 1, 6, 3, 4, 8, 2, 5 };
            IntNumberSystemConverter ic = new IntNumberSystemConverter(64);
            foreach (char c in str)
            {
                sum += ((byte)c) * dg[i];
                i++;
                if (i >= 9) break;
            }
            sum = 64 - sum % 63;
            return ic.ConvertToString(sum)[0];
        }

        public static DateTime ParseGenNo(string code)
        {
            if (string.IsNullOrEmpty(code) || code.Length != 10)
            { return DateTime.MinValue; }
            var seqConv = SequenceGen[converter.CharToNumber(code[1])];
            return baseTime.AddSeconds(seqConv.Parse(code.Substring(2, 5)));
        }

        public static SequenceNo CreateByGen(char type)
        {
            int seed = GetNextRandomSeed(64);

            SequenceNo id = new SequenceNo(0);

            id.buffer = new char[] { type, converter.NumberToChar(seed), '0', '0', '0', '0', '0', '0', '0', '0' };

            var gen = SequenceGen[seed];

            int ts = Convert.ToInt32((DateTime.Now - baseTime).TotalSeconds);

            gen.NumberToArray(ts, id.buffer, 10, 5, 3);

            gen.NumberToArray((Counter++ % 4096), id.buffer, 10, 2, 1);

            id.buffer[9] = CalcHash(id.buffer);

            return id;
        }

        public static bool CheckGenNo(string key)
        {
            if (string.IsNullOrEmpty(key)) return false;
            if (key.Length != 10) return false;
            char[] chars = key.ToCharArray();
            int l = key.Length;
            char hash = CalcHash(chars);
            return hash == chars[l - 1];
        }

        public override string ToString()
        {
            return new string(buffer, 0, 10);
        }

        public override int GetHashCode()
        {
            return buffer.GetHashCode();
        }
    }

    /// <summary>
    /// 提供基本的进度转换功能进制转换器
    /// </summary>

    public class NumberSystemConverter
    {
        protected char[] _chars;
        protected int baseNum = 10;

        /// <summary>
        /// 创建一个进制转换器的实例
        /// </summary>
        /// <param name="BaseNumber">进制数</param>
        /// <exception cref="ArgumentOutOfRangeException">BaseNumber 取值范围2-64</exception>
        public NumberSystemConverter(int BaseNumber)
        {
            if (BaseNumber < 2 || BaseNumber > 64)
            {
                throw new ArgumentOutOfRangeException();
            }
            baseNum = BaseNumber;
            _chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz$-".ToCharArray();
        }

        /// <summary>
        /// 将字符表示形式转换为长整型数值
        /// </summary>
        /// <param name="str">字符</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>      
        public unsafe virtual long ConvertToNumber(string str)
        {
            long ret = 0;
            if (string.IsNullOrEmpty(str))
            {
                throw new ArgumentNullException();
            }
            fixed (char* p = str)
            {
                char ch = p[0];
                int l = str.Length, j = 0;
                char* ptr = p;
                while (j < l)
                {
                    int dg = 0;
                    if (ch >= '0' && ch <= '9')
                    {
                        dg = ch - '0';
                    }
                    else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
                    {
                        dg = 10 + ch - ((ch >= 'a') ? 'a' : 'A');
                    }
                    else if (ch == '#')
                    {
                        dg = 63;
                    }
                    else if (ch == '$')
                    {
                        dg = 64;
                    }
                    long t = dg;
                    int max = l - j - 1;
                    for (int i = 0; i < max; i++)
                    {
                        t *= baseNum;
                    }
                    ret += t;
                    j++;
                    ch = *(++ptr);
                }
            }

            return ret;
        }
        /// <summary>
        /// 将长整弄数值转换为字符表示法
        /// </summary>
        /// <param name="value">长整形值</param>
        /// <returns></returns>
        public unsafe virtual string ConvertToString(long value)
        {
            if (value <= 0) return "0";
            int j = 0;
            long v = value;
            while (v != 0)
            {
                v = Convert.ToInt64(v / baseNum);
                j++;
            }
            char[] arr = new char[j];
            fixed (char* p = arr, pChars = _chars)
            {
                char* ptr = p;
                int i = 0;
                v = value;
                while (v != 0)
                {
                    long delta = v % baseNum;
                    v = Convert.ToInt64(v / baseNum);
                    *(ptr + (j - i - 1)) = *(pChars + delta);
                    i++;
                }
            }
            return new string(arr);
        }

        /// <summary>
        /// 将长整弄数值转换为字符表示法
        /// </summary>
        /// <param name="value">长整形值</param>
        /// <param name="digitLength">指定填充长度</param>
        /// <returns></returns>
        public string ConvertToString(long value, int digitLength)
        {
            string str = ConvertToString(value);
            int l = str.Length;
            if (l < digitLength)
            {
                return str.PadLeft(digitLength, '0');
            }
            return str;
        }
    }


    /// <summary>
    /// 提供整型进制转换的转换器
    /// </summary>
    public class IntNumberSystemConverter : NumberSystemConverter
    {
        public IntNumberSystemConverter(int BaseNumber)
            : base(BaseNumber)
        { }


        /// <summary>
        /// 将字符表示形式转换为整型数值
        /// </summary>
        /// <param name="str">字符</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public int ConvertToInt(string str)
        {
            return Convert.ToInt32(base.ConvertToNumber(str));
        }

        /// <summary>
        /// 将整型数值转换为字符表示法
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public string ConvertToString(int value)
        {
            return base.ConvertToString(value);
        }
    }
}
